use std::collections::HashMap;
use chrono::Local;
use crate::log_config::{Level, WD_LOG_CONFIG};

pub struct Output {
    prefix: Vec<String>,
    kv:Vec<String>,
}

impl Default for Output {
    fn default() -> Self {
        let mut log = Output::new();
        if WD_LOG_CONFIG.print_time {
            let now = Local::now().format("%Y-%m-%d %H:%M:%S%.3f ");
            log = log.prefix(now);
        }
        return log
    }
}
impl Output {
    pub fn new()-> Output {
        Self{prefix:vec![],kv :vec![]}
    }
    pub fn prefix<S : ToString>(mut self,s:S)->Self{
        self.prefix.push(s.to_string());self
    }
    pub fn field<K : ToString,V:ToString>(mut self,key:K,val:V)->Self{
        self.kv.push(key.to_string());
        self.kv.push(val.to_string());
        self
    }
    pub fn fields(mut self,map:HashMap<String,String>)->Self{
        for (k,v) in map.into_iter() {
            self.kv.push(k);
            self.kv.push(v);
        }
        self
    }
    pub fn format(self,level:Level)->String{
        let mut s = level.to_string();
        s.push_str(" ");
        for i in self.prefix.into_iter(){
            s.push_str(i.as_str());
            s.push_str(" ");
        }
        for i in self.kv.into_iter(){
            if s.ends_with(" ") {
                s.push_str( i.as_str());
            }else{
                s.push_str("=");
                s.push_str( i.as_str());
                s.push_str(" ");
            }
        }
        let end = s.len();
        s.remove(end -1);
        return s
    }
    pub fn panic<S:ToString>(self,content:S){
        Self::output(self,content,Level::PANIC)
    }
    pub fn error<S:ToString>(self,content:S){
        Self::output(self,content,Level::ERROR)
    }
    pub fn warn<S:ToString>(self,content:S){
        Self::output(self,content,Level::WARN)
    }
    pub fn info<S:ToString>(self,content:S){
        Self::output(self,content,Level::INFO)
    }
    pub fn debug<S:ToString>(self,content:S){
        Self::output(self,content,Level::DEBUG)
    }

    fn output<S:ToString>(self,content:S,level:Level){
        let s = self.field("content",content.to_string()).format(level);
        if WD_LOG_CONFIG.is_std_out {
            match level {
                Level::PANIC => println!("\x1b[7;31m{}\x1b[0m",s),
                Level::ERROR => println!("\x1b[7;31m{}\x1b[0m",s),
                Level::WARN => println!("\x1b[33m{}\x1b[0m",s),
                Level::INFO => println!("\x1b[32m{}\x1b[0m",s),
                Level::DEBUG => println!("\x1b[32m{}\x1b[0m",s),
            }
        }
        if WD_LOG_CONFIG.is_file_out {
            let mut out = WD_LOG_CONFIG.out.lock().unwrap();
            if let Err(e) = out.write_all(s.as_bytes()) {
                println!("write log to file error:{}",e);
            }
        }
    }
}

pub fn log_prefix<S:ToString>(content:S)->Output{
    Output::default().prefix(content)
}
pub fn log_field<K : ToString,V:ToString>(key:K,val:V)->Output{
    Output::default().field(key,val)
}
pub fn log_fields(map:HashMap<String,String>)->Output{
    Output::default().fields(map)
}